package com.rbac.api.aop;

import com.alibaba.fastjson.JSON;
import com.rbac.utils.commUtils.LogUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

///请求日志记录aop
@Aspect
@Component
public class RequestLogsAspect {



    ///日志类
    private final static LogUtil logger = LogUtil.getLogger(RequestLogsAspect.class);


    ///捕捉的切面
    @Pointcut("@annotation(com.rbac.api.annotation.RequestLogsAnnotation)")
    public void requestLogsAspect() {
    }


    ///前置操作，执行方法体之前先记录请求体内的参数
    @Before("requestLogsAspect()")
    public void beforeRequestLog(JoinPoint joinPoint){

        ///获取请求体
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        ///获取请求方式
        String method = request.getMethod();
        ///请求地址
        String url = request.getRequestURI();
        ///类方法
        String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();

        ///获取请求参数
        String paramsStr = "";
        Object[] args = joinPoint.getArgs();
        if(args.length>0){
            if("POST".equals(method)){
                Object object = args[0];
                Map map = getKeyAndValue(object);///获取post请求参数
                paramsStr = JSON.toJSONString(map);
            }else if("GET".equals(method)){ //Get方式请求参数
                paramsStr = request.getQueryString();
            }
        }


        ///日志模板
        String Template = "请求方式：%s ；请求地址：%s ；类方法：%s ；请求参数：%s 。";
        ///记录日志
        logger.error(String.format(Template, method, url, classMethod, paramsStr));


    }


    ///获取post请求参数
    private static Map<String, Object> getKeyAndValue(Object obj) {
        Map<String, Object> map = new HashMap<>();
        // 得到类对象
        Class userCla = (Class) obj.getClass();
        /* 得到类中的所有属性集合 */
        Field[] fs = userCla.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            f.setAccessible(true);
            // 设置些属性是可以访问的
            Object val = new Object();
            try {
                val = f.get(obj);
                // 得到此属性的值
                map.put(f.getName(), val);
                // 设置键值
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return map;
    }



    ///捕捉方法内抛出的异常
    @AfterThrowing(value = "requestLogsAspect()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        if( !(ex instanceof MethodArgumentNotValidException) ){
            ///
            logger.error(joinPoint.getSignature().getName()+" 的异常返回值："+ex);
        }

    }



    ///记录方法内正常返回内容
    @AfterReturning(returning = "ret", pointcut = "requestLogsAspect()")
    public void doAfterReturning(JoinPoint joinPoint,Object ret) throws Throwable {
        ///处理完请求，返回内容
        logger.error(joinPoint.getSignature().getName()+" 的 RESPONSE："+ret);
    }


}

